/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.xuexiang.xui_lib.component;

import com.xuexiang.xui_lib.component.status.StateChangeListenerImpl;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.DirectionalLayout;
import ohos.app.Context;

import java.util.ArrayList;
import java.util.List;

/**
 * 动画布局
 *
 * @author jiangjianming
 * @since 2021-04-13
 */
public class AnimatorLayout extends DirectionalLayout
    implements Component.BindStateChangedListener, Component.ClickedListener {
    private final List<Component> mChildList = new ArrayList<>();

    private boolean isOpen;
    private boolean isStarting;

    private AnimatorGroup mShowAnimatorGroup;
    private AnimatorGroup mHideAnimatorGroup;
    private OnMenuClickListener mMenuClickListener;
    private OnAnimatorChangeListener mOnAnimatorChangeListener;


    /**
     * 消失动画前执行
     *
     * @since 2021-04-13
     */
    public interface OnAnimatorChangeListener {
        /**
         * 动画开启的时候
         */
        void onStartAnimator();

        /**
         * 动画结束的时候
         */
        void onDismissAnimator();
    }

    /**
     * 菜单点击监听事件
     *
     * @since 2021-04-13
     */
    public interface OnMenuClickListener {
        /**
         * 点击菜单栏
         *
         * @param component 菜单组件
         */
        void onClickMenu(Component component);
    }

    /**
     * 动画布局
     *
     * @param context 上下文
     */
    public AnimatorLayout(Context context) {
        this(context, null);
    }

    /**
     * 动画布局
     *
     * @param context 上下文
     * @param attrSet 布局参数
     */
    public AnimatorLayout(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    /**
     * 动画布局
     *
     * @param context 上下文
     * @param attrSet 布局参数
     * @param styleName 样式
     */
    public AnimatorLayout(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        setBindStateChangedListener(this);
    }

    /**
     * 显示菜单子View
     */
    public void showAllChild() {
        // 没有打开过或者正在执行动画
        if (isOpen || isStarting) {
            return;
        }
        if (mChildList.size() <= 0) {
            return;
        }
        if (mOnAnimatorChangeListener != null) {
            mOnAnimatorChangeListener.onStartAnimator();
        }
        setVisibility(VISIBLE);
        mShowAnimatorGroup.start();
    }

    /**
     * 隐藏子View菜单
     */
    public void dismissAllChild() {
        // 没有打开过或者正在执行动画
        if (!isOpen || isStarting) {
            return;
        }
        if (mChildList.size() <= 0) {
            return;
        }
        if (mOnAnimatorChangeListener != null) {
            mOnAnimatorChangeListener.onDismissAnimator();
        }
        setVisibility(VISIBLE);
        mHideAnimatorGroup.start();
    }

    public boolean isOpen() {
        return isOpen;
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
        getChildComponents();
        generateShowAnimatorGroup();
        generateHideAnimatorGroup();
        setVisibility(HIDE);
    }

    @Override
    public void onClick(Component component) {
        if (mMenuClickListener != null) {
            mMenuClickListener.onClickMenu(component);
        }
        dismissAllChild();
    }

    private void generateHideAnimatorGroup() {
        mHideAnimatorGroup = new AnimatorGroup();
        AnimatorGroup.Builder build = mHideAnimatorGroup.build();
        for (int i = 0; i < mChildList.size(); i++) {
            Component component = mChildList.get(i);
            AnimatorProperty hideAnimator = createHideAnimator(component);
            hideAnimator.setDuration(i * 20);
            build.addAnimators(hideAnimator);
            hideAnimator.setStateChangedListener(new StateChangeListenerImpl() {
                @Override
                public void onStart(Animator animator) {
                    AnimatorProperty an = (AnimatorProperty) animator;
                    an.getTarget().setVisibility(VISIBLE);
                }

                @Override
                public void onEnd(Animator animator) {
                    AnimatorProperty animatorProperty = (AnimatorProperty) animator;
                    animatorProperty.getTarget().setVisibility(HIDE);
                }
            });
        }
        mHideAnimatorGroup.setStateChangedListener(new StateChangeListenerImpl() {
            @Override
            public void onStart(Animator animator) {
                isStarting = true;
            }

            @Override
            public void onEnd(Animator animator) {
                setVisibility(HIDE);
                isOpen = false;
                isStarting = false;
            }
        });
    }

    private void generateShowAnimatorGroup() {
        mShowAnimatorGroup = new AnimatorGroup();
        AnimatorGroup.Builder build = mShowAnimatorGroup.build();
        for (int i = mChildList.size() - 1; i >= 0; i--) {
            Component component = mChildList.get(i);
            component.setVisibility(HIDE);
            AnimatorProperty showAnimator = createShowAnimator(component);
            showAnimator.setDuration(i * 18);
            build.addAnimators(showAnimator);
            showAnimator.setStateChangedListener(new StateChangeListenerImpl() {
                @Override
                public void onStart(Animator animator) {
                    AnimatorProperty an = (AnimatorProperty) animator;
                    an.getTarget().setVisibility(VISIBLE);
                }
            });
        }
        mShowAnimatorGroup.setStateChangedListener(new StateChangeListenerImpl() {
            @Override
            public void onStart(Animator animator) {
                isStarting = true;
            }

            @Override
            public void onEnd(Animator animator) {
                isOpen = true;
                isStarting = false;
            }
        });
    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
    }

    public void setOnDismissListener(OnAnimatorChangeListener dismissListener) {
        this.mOnAnimatorChangeListener = dismissListener;
    }

    public void setMenuClickListener(OnMenuClickListener clickListener) {
        this.mMenuClickListener = clickListener;
    }

    private AnimatorProperty createShowAnimator(Component component) {
        AnimatorProperty animatorProperty = new AnimatorProperty();
        animatorProperty.setCurveType(Animator.CurveType.CUSTOMIZED);
        animatorProperty.scaleXFrom(0);
        animatorProperty.scaleYFrom(0);
        animatorProperty.scaleX(1.0F);
        animatorProperty.scaleY(1.0F);
        animatorProperty.setTarget(component);
        return animatorProperty;
    }

    private AnimatorProperty createHideAnimator(Component component) {
        AnimatorProperty animatorProperty = new AnimatorProperty();
        animatorProperty.setCurveType(Animator.CurveType.CUSTOMIZED);
        animatorProperty.scaleXFrom(1.0F);
        animatorProperty.scaleYFrom(1.0F);
        animatorProperty.scaleX(0.0F);
        animatorProperty.scaleY(0.0F);
        animatorProperty.setTarget(component);
        return animatorProperty;
    }

    private void getChildComponents() {
        mChildList.clear();
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            Component component = getComponentAt(i);
            mChildList.add(component);
            component.setClickedListener(this);
        }
    }
}
